package com.riccardocardin.structured.concurrency.application;

import com.riccardocardin.structured.concurrency.service.GitHubUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.StructuredTaskScope;

import static com.riccardocardin.structured.concurrency.model.Model.GitHubUser;
import static com.riccardocardin.structured.concurrency.model.Model.UserId;

public class GitHubUserStructuredConcurrentAppService implements GitHubUserApplicationService {

    private static final Logger LOGGER = LoggerFactory.getLogger("GitHubApp");

    private final GitHubUserService gitHubUserService;

    public GitHubUserStructuredConcurrentAppService(GitHubUserService gitHubUserService) {
        this.gitHubUserService = gitHubUserService;
    }

    @Override
    public GitHubUser findGitHubUser(UserId userId) throws InterruptedException, ExecutionException {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            var user = scope.fork(() -> gitHubUserService.findUser(userId));
            var repositories = scope.fork(() -> gitHubUserService.findRepositories(userId));
            scope.join().throwIfFailed();
            LOGGER.info("Both forked task completed");
            return new GitHubUser(user.get(), repositories.get());
        }
    }

    // or use the generic Concurrents.par util method
    /*@Override
    public GitHubUser findGitHubUser(UserId userId) throws InterruptedException, ExecutionException {
        var result = Concurrents.par(
                () -> gitHubUserService.findUser(userId),
                () -> gitHubUserService.findRepositories(userId)
        );
        return new GitHubUser(result.first(), result.second());
    }*/
}
